/*
 * @(#)DynamicClassLoader.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.framework;

import java.io.FileInputStream;
import java.util.Hashtable;

/**
 * <p>Class Name:    DynamicClassLoader.java    </p>
 * <p>Description:   This class is the class loader to load class dynamically.</p>
 *
 * @author           Rollo Chan
 * @company          DCIVision Limited
 * @creation date    04/09/2003
 * @version          $Revision: 1.7 $
 */

public class DynamicClassLoader {

  public static final String REVISION = "$Revision: 1.7 $";

  InnerDynamicClassLoader classLoader = null;

  public DynamicClassLoader() {
    this.classLoader = new InnerDynamicClassLoader();
  }

  public DynamicClassLoader(ClassLoader classLoader) {
    this.classLoader = new InnerDynamicClassLoader(classLoader);
  }

  public Class loadClass(String className) throws ClassNotFoundException {
    return (this.loadClass(className, true));
  }

  public synchronized Class loadClass(String className, boolean resolveIt) throws ClassNotFoundException {
    return (this.classLoader.loadClass(className, resolveIt));
  }

  public void reload() {
    this.classLoader = new InnerDynamicClassLoader(classLoader.getParent());
  }
}

// Private class of the real class loader.
class InnerDynamicClassLoader extends ClassLoader {
  private Hashtable classes = new Hashtable();
  private String basePath = "E:/temp/";

  public InnerDynamicClassLoader() {
    super();
  }

  public InnerDynamicClassLoader(ClassLoader classLoader) {
    super(classLoader);
  }

  private byte[] getClassFromUserDefinedPath(String className) {
    byte result[];
    try {
      FileInputStream fi = new FileInputStream(basePath + className + ".class");
      result = new byte[fi.available()];
      fi.read(result);
      return result;
    } catch (Exception e) {
      return null;
    }
  }

  public Class loadClass(String className) throws ClassNotFoundException {
    return (this.loadClass(className, true));
  }

  public synchronized Class loadClass(String className, boolean resolveIt) throws ClassNotFoundException {
    Class result;
    byte  classData[];

    /* Check our local cache of classes */
    result = (Class)classes.get(className);
    if (result != null) {
      return result;
    }

    /* Check with the primordial class loader */
    try {
      result = super.findSystemClass(className);
      return result;
    } catch (ClassNotFoundException e) {
    }

    /* Try to load it from current library path */
    try {
      result = Class.forName(className);
      return result;
    } catch (ClassNotFoundException e) {
    }

    /* Try to load it from our repository */
    classData = getClassFromUserDefinedPath(className);
    if (classData == null) {
      throw new ClassNotFoundException();
    }

    /* Define it (parse the class file) */
    result = defineClass(className, classData, 0, classData.length);
    if (result == null) {
      throw new ClassFormatError();
    }

    /* Resolve the associated classes or not */
    if (resolveIt) {
      resolveClass(result);
    }

    /* Cache it or not. */
    classes.put(className, result);

    return result;
  }

  public void setBasePath(String path) {
    this.basePath = path;
  }
}
